﻿/*****************************************************************************
 * Qwt Examples - Copyright (C) 2002 Uwe Rathmann
 * This file may be used under the terms of the 3-clause BSD License
 *****************************************************************************/

#include "BarChart.h"

#include <QwtPlotRenderer>
#include <QwtPlotCanvas>
#include <QwtPlotBarChart>
#include <QwtColumnSymbol>
#include <QwtPlotLayout>
#include <QwtLegend>
#include <QwtScaleDraw>
#include <QwtText>

#include <QApplication>
#include <QPainter>

namespace
{
class ScaleDraw : public QwtScaleDraw
{
public:
    ScaleDraw(Qt::Orientation orientation, const QStringList& labels) : m_labels(labels)
    {
        setTickLength(QwtScaleDiv::MinorTick, 0);
        setTickLength(QwtScaleDiv::MediumTick, 0);
        setTickLength(QwtScaleDiv::MajorTick, 2);

        enableComponent(QwtScaleDraw::Backbone, false);

        if (orientation == Qt::Vertical) {
            setLabelRotation(-60.0);
        } else {
            setLabelRotation(-20.0);
        }

        setLabelAlignment(Qt::AlignLeft | Qt::AlignVCenter);
    }

    virtual QwtText label(double value) const QWT_OVERRIDE
    {
        QwtText lbl;

        const int index = qRound(value);
        if (index >= 0 && index < m_labels.size()) {
            lbl = m_labels[ index ];
        }

        return lbl;
    }

private:
    const QStringList m_labels;
};

class ChartItem : public QwtPlotBarChart
{
public:
    ChartItem() : QwtPlotBarChart("Page Hits")
    {
        setLegendMode(QwtPlotBarChart::LegendBarTitles);
        setLegendIconSize(QSize(10, 14));
        setLayoutPolicy(AutoAdjustSamples);
        setLayoutHint(4.0);  // minimum width for a single bar

        setSpacing(10);  // spacing between bars
    }

    void addDistro(const QString& distro, const QColor& color)
    {
        m_colors += color;
        m_distros += distro;
        itemChanged();
    }

    virtual QwtColumnSymbol* specialSymbol(int index, const QPointF&) const QWT_OVERRIDE
    {
        // we want to have individual colors for each bar

        QwtColumnSymbol* symbol = new QwtColumnSymbol(QwtColumnSymbol::Box);
        symbol->setLineWidth(2);
        symbol->setFrameStyle(QwtColumnSymbol::Raised);

        QColor c(Qt::white);
        if (index >= 0 && index < m_colors.size())
            c = m_colors[ index ];

        symbol->setBrush(c);

        return symbol;
    }

    virtual QwtText barTitle(int sampleIndex) const QWT_OVERRIDE
    {
        QwtText title;
        if (sampleIndex >= 0 && sampleIndex < m_distros.size())
            title = m_distros[ sampleIndex ];

        return title;
    }

private:
    QList< QColor > m_colors;
    QList< QString > m_distros;
};

}

BarChart::BarChart(QWidget* parent) : QwtPlot(parent)
{
    const struct
    {
        const char* distro;
        const int hits;
        QColor color;

    } pageHits[] = { { "Arch", 1114, QColor("DodgerBlue") },    { "Debian", 1373, QColor("#d70751") },
                     { "Fedora", 1638, QColor("SteelBlue") },   { "Mageia", 1395, QColor("Indigo") },
                     { "Mint", 3874, QColor(183, 255, 183) },   { "openSuSE", 1532, QColor(115, 186, 37) },
                     { "Puppy", 1059, QColor("LightSkyBlue") }, { "Ubuntu", 2391, QColor("FireBrick") } };

    setAutoFillBackground(true);
    setPalette(QColor("Linen"));

    QwtPlotCanvas* canvas = new QwtPlotCanvas();
    canvas->setLineWidth(2);
    canvas->setFrameStyle(QFrame::Box | QFrame::Sunken);
    canvas->setBorderRadius(10);

    QPalette canvasPalette(QColor("Plum"));
    canvasPalette.setColor(QPalette::WindowText, QColor("Indigo"));
    canvas->setPalette(canvasPalette);

    setCanvas(canvas);

    setTitle("DistroWatch Page Hit Ranking, April 2012");

    ChartItem* chartItem = new ChartItem();

    QVector< double > samples;

    for (uint i = 0; i < sizeof(pageHits) / sizeof(pageHits[ 0 ]); i++) {
        m_distros += pageHits[ i ].distro;
        samples += pageHits[ i ].hits;

        chartItem->addDistro(pageHits[ i ].distro, pageHits[ i ].color);
    }

    chartItem->setSamples(samples);
    chartItem->attach(this);

    m_chartItem = chartItem;

    insertLegend(new QwtLegend());

    setOrientation(0);
    setAutoReplot(false);
}

void BarChart::setOrientation(int o)
{
    const Qt::Orientation orientation = (o == 0) ? Qt::Vertical : Qt::Horizontal;

    int axis1 = QwtAxis::XBottom;
    int axis2 = QwtAxis::YLeft;

    if (orientation == Qt::Horizontal)
        qSwap(axis1, axis2);

    m_chartItem->setOrientation(orientation);

    setAxisTitle(axis1, "Distros");
    setAxisMaxMinor(axis1, 3);
    setAxisScaleDraw(axis1, new ScaleDraw(orientation, m_distros));

    setAxisTitle(axis2, "Hits per day ( HPD )");
    setAxisMaxMinor(axis2, 3);

    QwtScaleDraw* scaleDraw = new QwtScaleDraw();
    scaleDraw->setTickLength(QwtScaleDiv::MediumTick, 4);
    setAxisScaleDraw(axis2, scaleDraw);

    plotLayout()->setCanvasMargin(0);
    replot();
}

void BarChart::exportChart()
{
    QwtPlotRenderer renderer;
    renderer.exportTo(this, "distrowatch.pdf");
}

void BarChart::doScreenShot()
{
    exportPNG(800, 600);
}

void BarChart::exportPNG(int width, int height)
{
    const QString fileBase = QString("distrowatch-%2x%3").arg(width).arg(height);

    const int resolution = qRound(85.0 * width / 800.0);

    const double mmToInch  = 1.0 / 25.4;
    const int dotsPerMeter = qRound(resolution * mmToInch * 1000.0);

    QImage image(width, height, QImage::Format_ARGB32);
    image.setDotsPerMeterX(dotsPerMeter);
    image.setDotsPerMeterY(dotsPerMeter);

    image.fill(Qt::transparent);

    QPainter painter(&image);
    render(&painter, QRectF(0, 0, width, height));
    painter.end();

    image.save(fileBase + ".png");
}

void BarChart::render(QPainter* painter, const QRectF& targetRect)
{
    const int r           = 20;
    const QRectF plotRect = targetRect.adjusted(0.5 * r, 0.5 * r, -0.5 * r, -0.5 * r);

    QwtPlotRenderer renderer;

    if (qApp->styleSheet().isEmpty()) {
        renderer.setDiscardFlag(QwtPlotRenderer::DiscardBackground, true);

        painter->save();
        painter->setRenderHint(QPainter::Antialiasing, true);
        painter->setPen(QPen(Qt::darkGray, 1));
        painter->setBrush(QColor("WhiteSmoke"));
        painter->drawRoundedRect(targetRect, r, r);
        painter->restore();
    }

    renderer.render(this, painter, plotRect);
}

#include "moc_BarChart.cpp"
